// axios配置  可自行根据项目进行更改，只需更改该文件即可，其他文件可以不动
import { VAxios } from './Axios'
import { AxiosTransform } from './axiosTransform'
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'
import qs from 'qs'
import { checkStatus } from './checkStatus'
import { Modal, message as Message } from 'ant-design-vue'
import { RequestEnum, ContentTypeEnum, StatusEnum } from '~/enums/httpEnum'

import { isString } from '~/utils/is'
import { setObjToUrlParams } from '~/utils/urlUtils'

import { RequestOptions, Result } from './types'

const isDev = import.meta.env.MODE === 'development'
import { router } from '~/modules/router'
import { storage } from '~/utils/Storage'
import useUserStore from '~/stores/user'

/**
 * @description: 数据处理，方便区分多种处理方式
 */
const transform: AxiosTransform = {
  /**
   * @description: 处理请求数据
   */
  transformRequestData: (
      res: AxiosResponse<Result>,
      options: RequestOptions,
  ) => {
    const {
      isTransformRequestResult,
      isShowMessage = true,
      successMessageText,
      errorMessageText,
    } = options

    if (!res?.data) {
      throw new Error('网络请求发生异常')
    }

    const isDataStructureCorrect =
        Reflect.has(res.data, 'status') &&
        Reflect.has(res.data, 'data') &&
        Reflect.has(res.data, 'message')
    if (!isDataStructureCorrect)
      throw new Error('返回的数据结构不正确,必须包含 status, data, message')

    // 不进行任何处理，直接返回
    // 用于页面代码可能需要直接获取code，data，message这些信息时开启
    if (!isTransformRequestResult) {
      return res.data
    }

    //  这里 code，result，message为 后台统一的字段，需要在 types.ts内修改为项目自己的接口返回格式
    const { status, data, message } = res.data

    // 是否显示正确后的提示信息，发生错误无论如何均要提示
    if (status === StatusEnum.SUCCESS) {
      isShowMessage &&
      Message.success(successMessageText || message || '操作成功！')
    } else {
      Message.error(errorMessageText || message || '操作失败！')
    }

    // 接口请求成功，直接返回结果
    if (status === StatusEnum.SUCCESS) {
      return data
    }

    // 接口请求错误，统一提示错误信息
    if (status === StatusEnum.ERROR) {
      return Promise.reject(
          new Error(errorMessageText || message || '操作失败！'),
      )
    }

    // 登录超时
    if (status === StatusEnum.TIMEOUT) {
      if (router.currentRoute.value.name == 'login') return
      // 到登录页
      const timeoutMsg = '登录超时,请重新登录!'
      Modal.destroyAll()
      Modal.warning({
        title: '提示',
        content: '登录身份已失效,请重新登录!',
        onOk: () => {
          return router
              .replace({
                name: 'login',
                query: {
                  redirect: router.currentRoute.value.fullPath,
                },
              })
              .finally(() => {
                storage.clear()
              })
        },
      })
      return Promise.reject(new Error(timeoutMsg))
    }

    return Promise.reject(new Error('发生未知异常'))
  },

  // 请求之前处理config
  beforeRequestHook: (config, options) => {
    const { apiUrl, urlPrefix, joinParamsToUrl, isParseToJson = true } = options

    config.url = isDev
        ? `${urlPrefix}${config.url}`
        : `${apiUrl || ''}${config.url}`

    if (config.method === RequestEnum.GET) {
      const now = new Date().getTime()
      if (!isString(config.params)) {
        config.data = {
          // 给 get 请求加上时间戳参数，避免从缓存中拿数据。
          params: Object.assign(config.params || {}, {
            _t: now,
          }),
        }
      } else {
        // 兼容restful风格
        config.url = config.url + config.params + `?_t=${now}`
        config.params = {}
      }
    } else {
      if (!isString(config.params)) {
        config.data = config.params
        config.params = {}
        if (joinParamsToUrl) {
          config.url = setObjToUrlParams(config.url as string, config.data)
        }
      } else {
        // 兼容restful风格
        config.url = config.url + config.params
        config.params = {}
      }
      // 'a[]=b&a[]=c'
      if (!isParseToJson) {
        config.params = qs.stringify(config.params, { arrayFormat: 'brackets' })
        config.data = qs.stringify(config.data, { arrayFormat: 'brackets' })
      }
    }
    return config
  },

  /**
   * @description: 请求拦截器处理
   */
  requestInterceptors: (config: AxiosRequestConfig) => {
    // 请求之前处理config
    const user = useUserStore()
    const token = user.token
    if (token) {
      // jwt token
      // @ts-ignore
      config.headers.token = token
    }
    return config
  },

  /**
   * @description: 响应错误处理
   */
  responseInterceptorsCatch: (error: any) => {
    const { response, code, message } = error || {}
    const msg: string =
        response && response.data && response.data.error
            ? response.data.error.message
            : ''
    const err: string = error.toString()
    try {
      if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) {
        Message.error('接口请求超时,请刷新页面重试!')
        return
      }
      if (err && err.includes('Network Error')) {
        Modal.confirm({
          title: '网络异常',
          content: '请检查您的网络连接是否正常!',
        })
        return
      }
    } catch (error: any) {
      throw new Error(error)
    }
    // 请求是否被取消
    const isCancel = axios.isCancel(error)
    if (!isCancel) {
      checkStatus(error.response && error.response.status, msg)
    } else {
      console.warn(error, '请求被取消！')
    }
    return error
  },

  // @ts-ignore
  requestCatch: (e) => e,
}

const Axios = new VAxios({
  timeout: 15 * 1000,
  // 基础接口地址
  // baseURL: 'http://172.16.81.63:8090',
  // 接口可能会有通用的地址部分，可以统一抽取出来
  // prefixUrl: prefix,
  headers: { 'Content-Type': ContentTypeEnum.JSON },
  // 数据处理方式
  transform,
  // 配置项，下面的选项都可以在独立的接口请求中覆盖
  requestOptions: {
    // 默认将prefix 添加到url
    joinPrefix: true,
    // url默认前缀，代理时使用
    // urlPrefix: '/api',
    urlPrefix: '',
    // 需要对返回数据进行处理
    isTransformRequestResult: true,
    // post请求的时候添加参数到url
    joinParamsToUrl: false,
    // 格式化提交参数时间
    formatDate: true,
    // 消息提示类型
    errorMessageMode: 'none',
    // 接口地址
    apiUrl: import.meta.env.VITE_APP_API_URL,
  },
  withCredentials: false,
})

export default Axios
